﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="DialogActivationBehavior.cs" company="http://buginbox.wordpress.com/">
//   Copyright (c) GNU General Public License version 2 (GPLv2)
// </copyright>
// --------------------------------------------------------------------------------------------------------------------

using System;
using System.Collections.Specialized;
using System.Windows;
using Microsoft.Practices.Prism.Regions;
using Microsoft.Practices.Prism.Regions.Behaviors;

namespace Wpf.Core.Behavior
{
    /// <summary>
    /// Defines a behavior that creates a Dialog to display the active view of the target <see cref="IRegion"/> .
    /// </summary>
    public abstract class DialogActivationBehavior : RegionBehavior, IHostAwareRegionBehavior
    {
        /// <summary>
        /// The key of this behavior
        /// </summary>
        public const string BehaviorKey = "DialogActivation";

        /// <summary>
        /// The content dialog.
        /// </summary>
        private IWindow _contentDialog;

        /// <summary>
        /// Gets or sets the <see cref="DependencyObject"/> that the <see cref="IRegion"/> is attached to.
        /// </summary>
        /// <value>
        /// A <see cref="DependencyObject"/> that the <see cref="IRegion"/> is attached to. This is usually a <see cref="FrameworkElement"/> that is part of the tree. 
        /// </value>
        public DependencyObject HostControl
        {
            get;
            set;
        }

        /// <summary>
        /// Performs the logic after the behavior has been attached.
        /// </summary>
        protected override void OnAttach()
        {
            Region.ActiveViews.CollectionChanged += ActiveViews_CollectionChanged;
        }

        /// <summary>
        /// Override this method to create an instance of the <see cref="IWindow"/> that will be shown when a view is activated.
        /// </summary>
        /// <returns>
        /// An instance of <see cref="IWindow"/> that will be shown when a view is activated on the target <see cref="IRegion"/> . 
        /// </returns>
        protected abstract IWindow CreateWindow();

        /// <summary>
        /// The active views_ collection changed.
        /// </summary>
        /// <param name="sender">
        /// The sender. 
        /// </param>
        /// <param name="e">
        /// The e. 
        /// </param>
        private void ActiveViews_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            if (e.Action == NotifyCollectionChangedAction.Add)
            {
                // this.CloseContentDialog();
                PrepareContentDialog(e.NewItems[0]);
            }
            else if (e.Action == NotifyCollectionChangedAction.Remove)
            {
                CloseContentDialog(((FrameworkElement)e.OldItems[0]).Parent as Window);
            }
        }

        /// <summary>
        /// The get style for view.
        /// </summary>
        /// <returns>
        /// The System.Windows.Style.
        /// </returns>
        private Style GetStyleForView()
        {
            return HostControl.GetValue(RegionPopupBehavior.ContainerWindowStyleProperty) as Style;
        }

        /// <summary>
        /// The prepare content dialog.
        /// </summary>
        /// <param name="view">
        /// The view. 
        /// </param>
        private void PrepareContentDialog(object view)
        {
            _contentDialog = CreateWindow();
            _contentDialog.Content = view;
            _contentDialog.Owner = HostControl;
            _contentDialog.Closed += ContentDialogClosed;

            var closable = view as IClosable;
            if (closable != null)
            {
                _contentDialog.Closing += (s, e) =>
                    {
                        if (closable.CanBeClosed != null)
                        {
                            e.Cancel = !closable.CanBeClosed.Invoke();
                        }
                    };
            }

            _contentDialog.Style = GetStyleForView();
            _contentDialog.Show();
        }

        /// <summary>
        /// The close content dialog.
        /// </summary>
        /// <param name="contentDialog">
        /// The content dialog. 
        /// </param>
        protected void CloseContentDialog(Window contentDialog)
        {
            if (contentDialog != null)
            {
                try
                {
                    contentDialog.Closed -= ContentDialogClosed;
                    contentDialog.Close();
                    contentDialog.Content = null;
                    contentDialog.Owner = null;
                }
                catch (InvalidOperationException)
                {
                    // En cas de fermeture depuis l'AutoLogOff
                    // cette erreur peut être générée en fonction de l'ordre de traitement des évènements
                    // Ne rien faire
                }
            }
        }

        /// <summary>
        /// The content dialog closed.
        /// </summary>
        /// <param name="sender">
        /// The sender. 
        /// </param>
        /// <param name="e">
        /// The e. 
        /// </param>
        protected void ContentDialogClosed(object sender, EventArgs e)
        {
            var window = sender as Window;

            if (window != null)
            {
                Region.Deactivate(window.Content);
                CloseContentDialog(window);
            }
        }
    }
}